#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Filename: req_bug_list.py
# Author: ChenChangSong
# Date: 2025-11-02

"""
功能描述: 需求关联的bug信息（内部bug数，线上bug数）
"""

import json
import time
import random

import sys
from pathlib import Path
sys.path.append(str(Path(__file__).resolve().parent.parent.parent))

from comm.common_code import *

def req_test_bug_info(req_id):
    """根据需求ID获取需求关联的测试bug信息(总bug个数，线上bug个数)"""
    excel_data = get_excel_data()
    bug_template_file = app_dir / 'files' / 'config_file' / 'bug_template.json'
    with open(bug_template_file, 'r', encoding='utf-8') as f:
        template_list = json.load(f) # 从json文件中读取bug模板列表

    url = "https://www.tapd.cn/api/entity/bugs/bugs_list"
    
    headers = {
    'authority': 'www.tapd.cn',
    'accept': 'application/json, text/plain, */*',
    'accept-language': 'zh-CN,zh;q=0.9',
    'content-type': 'application/json',
    'cookie':excel_data["Cookie"],
    'origin': 'https://www.tapd.cn',
    'referer': f'https://www.tapd.cn/tapd_fe/{excel_data["项目ID"]}/story/detail/{req_id}',
    'sec-ch-ua': '"Not)A;Brand";v="24", "Chromium";v="116"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    'sec-fetch-dest': 'empty',
    'sec-fetch-mode': 'cors',
    'sec-fetch-site': 'same-origin',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.562.400 QQBrowser/19.6.6725.400'
    }
    
    # 初始化变量
    invalid_status_list = ["同意拒绝","已拒绝（不予受理）","已确认未复现","拒绝(内部bug)","拒绝（线上：重复/非问题）","status_4","status_8","status_1","status_5"]
    invalid_online_bug_num = 0 # 无效线上bug
    invalid_test_bug_num = 0 # 无效内部bug
    effective_test_bug_num = 0  #有效内部bug
    effective_online_bug_num = 0  #有效线上bug
    total_bug = 0 # 总用bug数（包含线上)
    page = 1
    has_more_pages = True
    
    # 循环获取所有页面的数据
    while has_more_pages:
        # 构造payload，包含当前页码
        payload = json.dumps({
        "workspace_id": f"{excel_data['项目ID']}",
        "conf_id": "",
        "sort_name": "source",
        "confIdType": "URL",
        "order": "desc",
        "perpage": 100,
        "page": page,
        "filter_expr": {
            "data": [
            {
                "fieldOption": "like",
                "fieldType": "input",
                "entity": "bug",
                "fieldSystemName": "BugStoryRelation_relative_id",
                "selectOption": [],
                "value": f"{req_id}",
                "fieldIsSystem": "1"
            }
            ],
            "optionType": "AND"
        },
        "main_location": "",
        "location": "/prong/stories/relation_bugs",
        "show_fields": [],
        "dsc_token": "qeSs1MkPb6GKkSam"
        })
        
        # 发送请求，添加重试机制
        max_retries = 3
        retry_count = 0
        response_code = None
        response_data = None
        last_exception = None
        
        while retry_count <= max_retries:
            try:
                if retry_count > 0:
                    logger.info(f"开始API请求重试（尝试 {retry_count}/{max_retries}） - POST {url}")
                    
                response_code, response_data = api_request(method="POST", url=url, headers=headers, data=payload)
                
                # 如果响应正常，跳出重试循环
                if response_code == 200 and response_data:
                    if retry_count > 0:
                        logger.info(f"重试请求成功 - POST {url}")
                    break
                
                # 响应异常，准备重试
                error_msg = f"请求失败，响应码: {response_code}"
                
            except Exception as e:
                last_exception = e
                logger.error(f"请求异常: {e}")
                error_msg = f"请求异常: {str(e)}"
            
            # 如果还没达到最大重试次数，进行重试
            if retry_count < max_retries:
                # 指数退避策略，添加随机因子避免雪崩效应
                wait_time = min((2 ** retry_count) + random.uniform(0.5, 1.5), 30)  # 最大等待30秒
                logger.warning(f"{error_msg}，等待 {wait_time:.2f} 秒后重试 (尝试 {retry_count + 1}/{max_retries})")
                time.sleep(wait_time)
            else:
                logger.error(f"达到最大重试次数 ({max_retries})，请求失败 - POST {url}")
                if last_exception:
                    logger.error(f"最后一次异常: {last_exception}")
            
            retry_count += 1
        
        if response_code == 200:
            bugs_list = response_data["data"]['bugs_list']
            # logger.info(f"ccsbugs_list{bugs_list}")
            # 如果是第一页，获取总bug数
            if page == 1:
                total_bug = int(response_data["data"]["total_count"])
            
            if bugs_list != []:
                logger.info(f"正在处理第{page}页，共{len(bugs_list)}条bug数据")
                # 统计各类bug数量
                for bug in bugs_list:
                    try:
                        bug_data = bug.get("Bug", {})
                        # bug模板，安全获取source或template_id
                        source = bug_data.get("source", "")
                        template_id = bug_data.get("template_id", "")

                        # bug模板template_list = {"1166606973001000073": "线上模板","1166606973001000074": "内部模板"}
                        # 有时候不存在source，取template_id（source显示模板名称，template_id显示模板的id）
                        bug_template = source if source else template_list.get(template_id, "未知模板")#bug对应的bug模板
                        bug_status = bug_data.get("status", "") #bug对应的状态
                        if bug_template == "线上模板" and bug_status not in invalid_status_list: # 有效线上bug
                            effective_online_bug_num += 1
                        elif bug_template == "线上模板" and bug_status in invalid_status_list: # 无效线上bug
                            invalid_online_bug_num += 1
                        elif bug_template == "内部模板" and bug_status not in invalid_status_list: # 有效内部bug
                            effective_test_bug_num += 1
                        elif bug_template == "内部模板" and bug_status in invalid_status_list: # 无效内部bug
                            invalid_test_bug_num += 1
                        elif bug_template == "未知模板": # 未知模板
                            logger.warning(f"第{page}页含有未知模板的bug:{bug}")
                    except Exception as e:
                        logger.error(f"处理bug数据时出错: {str(e)}")
                        logger.error(f"问题bug数据: {bug}")
                        # 继续处理下一个bug，不中断循环
                
                # 检查每页bug数是否小于100，如果小于100说明已经是最后一页
                if len(bugs_list) < 100:
                    logger.info(f"第{page}页bug数小于100，已获取所有页面")
                    has_more_pages = False
                else:
                    # 增加页码，继续下一页
                    page += 1
            else:
                # 如果当前页没有数据，结束循环
                logger.info(f"第{page}页没有bug数据，已获取所有页面")
                has_more_pages = False
        else:
            logger.info(f"第{page}页bug获取失败，响应码{response_code}，响应内容{response_data}")
            has_more_pages = False
    
    logger.info(f"bug总数{total_bug}，共{effective_online_bug_num}个有效线上bug，{invalid_online_bug_num}个无效线上bug，{effective_test_bug_num}个有效内部bug，{invalid_test_bug_num}个无效内部bug")
    return total_bug, effective_online_bug_num, invalid_online_bug_num,effective_test_bug_num,invalid_test_bug_num

if __name__ == "__main__":
    # 1166606973001057648:2个线上,1166606973001056092:4个线上bug，1166606973001055108:缺少字段
    req_test_bug_info(req_id='1166606973001055108')
